package com.jh.paymentchannel.service.impl;

import cn.jh.common.exception.ServiceException;
import cn.jh.common.pay.client.FreeQuickClient;
import cn.jh.common.pay.client.FreeQuickRequest;
import cn.jh.common.pay.client.FreeQuickResponse;
import cn.jh.common.pay.enumtype.EncryptTypeEnum;
import cn.jh.common.pay.jdpush.PayBarException;
import cn.jh.common.pay.utils.EncryptType;
import cn.jh.common.pay.utils.PayBarClient;
import cn.jh.common.pay.utils.PayBarRequest;
import cn.jh.common.pay.utils.PayBarResponse;
import cn.jh.common.proxy.FreeQuickProxyService;
import cn.jh.common.utils.CommonConstants;
import cn.jh.common.utils.CommonsUtil;
import cn.jh.common.utils.DateUtil;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.ImmutableMap;
import com.jh.paymentchannel.pojo.freeQuick.FreeQuickOrder;
import com.jh.paymentchannel.pojo.freeQuick.FreeQuickWithdraw;
import com.jh.paymentchannel.pojo.freeQuick.FreeQuickWithdrawTemp;
import com.jh.paymentchannel.repository.freeQuick.FreeQuickOrderRepository;
import com.jh.paymentchannel.repository.freeQuick.FreeQuickWithdrawRepository;
import com.jh.paymentchannel.repository.freeQuick.FreeQuickWithdrawTempRepository;
import com.jh.paymentchannel.service.freeQuick.FreeQuickPayService;
import com.jh.paymentchannel.util.Util;
import com.jh.paymentchannel.util.WithDrawOrder;
import com.sun.org.apache.xpath.internal.operations.Mult;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.persistence.criteria.Predicate;
import java.math.BigDecimal;
import java.net.URI;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

import static cn.jh.common.utils.CommonConstants.PAYMENT_STATUS_PROCESS;
import static org.apache.commons.lang3.StringUtils.isEmpty;
import static org.apache.commons.lang3.StringUtils.isNotBlank;

@Service
public class FreeQuickPayServiceImpl implements FreeQuickPayService{

    private static final Logger log = LoggerFactory.getLogger(FreeQuickPayServiceImpl.class);

    @Autowired
    Util util;

    @Autowired
    private JdbcTemplate jdbcTemplate;


    @Autowired
    private FreeQuickOrderRepository freeQuickOrderRepository;

    @Autowired
    private FreeQuickWithdrawRepository freeQuickWithdrawRepository;

    @Autowired
    private FreeQuickWithdrawTempRepository freeQuickWithdrawTempRepository;

    @Transactional
    public List<FreeQuickWithdrawTemp> queryWithdrawTemp(){
        List<FreeQuickWithdrawTemp> result = freeQuickWithdrawTempRepository.queryWithdrawTemp();
        int count = 0;
        for(FreeQuickWithdrawTemp temp : result){
            temp.setPayStatus("4");

            freeQuickWithdrawTempRepository.save(temp);
            count ++;
        }
        if (count > 0) {
            for(FreeQuickWithdrawTemp temp : result){
                FreeQuickWithdraw  withdraw = new FreeQuickWithdraw();
                withdraw.setRequestNo(temp.getRequestNo());
                withdraw.setMerchantNo(temp.getMerchantNo());
                withdraw.setChannelCode(temp.getChannelId());
                withdraw.setUserId(temp.getUserId());
                withdraw.setInAmount(temp.getInAmount());
                withdraw.setAmount(temp.getAmount());
                withdraw.setPayType("1");
                try{
                    withdraw(withdraw);
                }catch (Exception e){
                    log.error("task freequick pram{} error" + e.getMessage());
                }
            }
        }

        return result;
    }

    /**
     * 查询是否交易
     * @return
     */
    @Transactional
    public List<FreeQuickWithdraw> getAllInProcessPay(){
        List<FreeQuickWithdraw> list = freeQuickWithdrawRepository.getAllInProcessPay();
        for(FreeQuickWithdraw order : list){
            queryWithdraw(order.getRequestNo(), order.getMerchantNo());
        }
        return list;
    }

    public List<FreeQuickOrder> getAllInProcessPayStatus(){
        return freeQuickOrderRepository.getAllInProcessPayStatus();
    }

    /**
     * 在线交易/交易
     * @param freeQuickOrder
     * @return
     * @throws Exception
     */
    @Transactional
    public Map payment(FreeQuickOrder freeQuickOrder) throws Exception {
        Map map = new HashMap();
        FreeQuickRequest request = new FreeQuickRequest(CommonConstants.AGENT_NO, CommonConstants.AGENT_KEY);
        request.setSupportSign(false);
        request.setEncryptType(EncryptTypeEnum.AES);
        String bankAccountNo = freeQuickOrder.getBankCardNo();
        String channelCode = freeQuickOrder.getChannelProductCode();

        //查询用户推荐人费率
        Map<String,Object> param = verifyBankInfo(bankAccountNo,freeQuickOrder.getUserId(),channelCode,"1");
        Map<String,Object> prams = MapUtils.getMap(param,"result");
        if (prams != null) {
            int gradeRate = (Integer) prams.getOrDefault("gradeRate","0");
            Map info = (Map) prams.getOrDefault("info","0");
            String brandUserId =  prams.getOrDefault("brandUserId","0").toString();
            String bran = prams.getOrDefault("brandRate","0").toString();
            BigDecimal grade = new BigDecimal(gradeRate);
            BigDecimal rate = freeQuickOrder.getRate();
            if(StringUtils.isBlank(bran) || bran.equals("null")){
                bran = "0.00";
            }
            BigDecimal brandRates = new BigDecimal(bran);
            BigDecimal inAmount = freeQuickOrder.getInAmount();//用户输入金额
            String pro = (String)prams.getOrDefault("preUserId", "0");
            int preUserId = 0;
            if(StringUtils.isNotBlank(pro)){
                preUserId = Integer.valueOf(pro);
            }

            //计算推荐人费率

            BigDecimal brandRa ;
            //推荐人
            if((gradeRate > 0)
                    && (preUserId != Integer.valueOf(brandUserId))){
                BigDecimal grades = rate.subtract(grade);
                BigDecimal gradeAmount = inAmount.multiply(grades);//获得推荐人手续费
                BigDecimal sum = gradeAmount.setScale(2,BigDecimal.ROUND_DOWN);
                freeQuickOrder.setGradeRate(grades);
                if(preUserId != 0){
                    freeQuickOrder.setPreUserId(preUserId+"");
                }
                freeQuickOrder.setGradeAmount(sum);
                brandRa = grades.subtract(brandRates);
                //保存推荐人分润
                verifyUserAccount(brandRa+"", preUserId+"");

            }else{
                if(brandRates.equals("0")){
                    brandRa = new BigDecimal(0);
                }else{
                    brandRa = rate.subtract(brandRates);
                }
            }

            if(StringUtils.isNotBlank(brandUserId)){
                //计算台卡代理商分润
                BigDecimal brandAmount = inAmount.multiply(brandRa);
                BigDecimal brandSum = brandAmount.setScale(2,BigDecimal.ROUND_DOWN);

                //保存台卡代理商分润
                verifyUserAccount(brandUserId, brandSum+"");
                freeQuickOrder.setBrandAmount(brandSum);
                freeQuickOrder.setBrandRate(brandRa);

                //brandUserId贴牌
                freeQuickOrder.setBrandUserId(brandUserId+"");
            }

            if(null == info){
                map.put("merchantNo", freeQuickOrder.getMerchantNo());
                map.put("bizCode", CommonConstants.FALIED);
                map.put("code", CommonConstants.FALIED);
                map.put("msg","信用卡信息不全");
                return map;
            }

            String securityCode = (String)info.getOrDefault("securityCode","0");
            String expiredTime = (String)info.getOrDefault("expiredTime","0");

            freeQuickOrder.setCvn2(securityCode);
            freeQuickOrder.setExpired(expiredTime);
            if (StringUtils.isBlank(freeQuickOrder.getRequestNo())) {
                String requestN = String.valueOf(System.currentTimeMillis());
                freeQuickOrder.setRequestNo(requestN);
            }

            request.addParam("requestNo", freeQuickOrder.getRequestNo());//请求流水号
            request.addParam("merchantNo",freeQuickOrder.getMerchantNo());//订单号
            request.addParam("channelProductCode", freeQuickOrder.getChannelTag());//通道产品编码
            request.addParam("bankCardNo", freeQuickOrder.getBankCardNo());//银行卡号
            request.addParam("amount", freeQuickOrder.getAmount());//金额
            request.addParam("cvn2", securityCode);//银行背面数字
            request.addParam("expired", expiredTime);//过期日期
            request.addParam("productName", freeQuickOrder.getProductName());//产品名称
            request.addParam("productDesc", freeQuickOrder.getProductDesc());//产品描述
            if (freeQuickOrder.getChannelProductCode().equals("5")) {
                request.addParam("clientIp", freeQuickOrder.getClientIp());//客户端P地址
                request.addParam("area", freeQuickOrder.getArea());//交易城市
            } else {
                request.addParam("clientIp", "");//客户端P地址
                request.addParam("area", "");//交易城市
            }

            request.addParam("serverCallbackUrl", CommonConstants.BASEURL_XJF + CommonConstants.BASEURL_WITHDRAW_CARD);//交易服务回调地址
            freeQuickOrder.setPayStatus("0");
            log.debug("response:" + request.toString());
            FreeQuickResponse response = FreeQuickClient.post(CommonConstants.BASEURL_PAYMENT, request);
            log.debug("response:" + JSON.toJSONString(response));
            Map<String, String> resp = response.getResultMap();
            String bizCode = resp.getOrDefault("bizCode", "0");
            String codes = resp.getOrDefault("code", "0");
            String bizMsg = resp.getOrDefault("bizMsg", "0");
            map.put("requestNo", freeQuickOrder.getRequestNo());
            map.put("merchantNo", freeQuickOrder.getMerchantNo());
            map.put("bizCode", bizCode);
            map.put("code", codes);

            //交易成功
            if (codes.equals(CommonConstants.FREE_SUCCESS)) {
                if (!bizCode.equals("1")) {
                    bizMsg = CommonsUtil.freeQuickError(bizCode);
                }
            } else {
                bizMsg = CommonsUtil.freeQuickError(bizCode);
            }
            map.put("msg",bizMsg);
            freeQuickOrder.setCode(response.getCode());
            freeQuickOrder.setBizMsg(response.getMessage());
            freeQuickOrder.setCreateTime(new Date());
            //保存交易信息
            freeQuickOrderRepository.save(freeQuickOrder);
        }

        return map;
    }


    /**
     * 生成提现任务
     * @param freeQuickWithdraw
     */
    public void saveWithdraw(FreeQuickWithdrawTemp freeQuickWithdraw){
        freeQuickWithdrawTempRepository.save(freeQuickWithdraw);

    }

    /**
     * 查询通道交易状态接口
     * @param requestNo
     * @param merchantNo
     * @return
     * @throws ServiceException
     */
    public void queryPay(String requestNo,String merchantNo) throws ServiceException {
        FreeQuickRequest request = new FreeQuickRequest(CommonConstants.AGENT_NO, CommonConstants.AGENT_KEY);
        request.setSupportSign(false);
        request.setEncryptType(EncryptTypeEnum.AES);
        request.addParam("requestNo", requestNo);//请求流水号
        request.addParam("merchantNo", merchantNo);//商户编号
        FreeQuickResponse response = FreeQuickClient.post(CommonConstants.BASEURL + CommonConstants.BASEURL_PAYM, request);
        String bizCode = "0", codes = "0", status = "0";
        if (response != null) {
            log.info("response:" + JSON.toJSONString(response));
            Map<String, String> resp = response.getResultMap();
            if (resp != null) {
                bizCode = resp.getOrDefault("bizCode", "0");
                codes = resp.getOrDefault("code", "0");
                status = resp.getOrDefault("status", "0");
            }
        }

        //交易是否成功
        if(CommonConstants.FREE_SUCCESS.equals(codes)){
            if(bizCode.equals("1")){
                if(org.apache.commons.lang.StringUtils.isNotBlank(status)){
                    String payStatus = CommonsUtil.queryStatus(status);
                    //更新交易状态
                    String sql = "update t_passageway_order set pay_status = " + payStatus + " where request_no = " + requestNo;
                    jdbcTemplate.update(sql);
                    //更新提现临时任务
                    String sql1 = "UPDATE t_withdraw_temporary set pay_status = " + payStatus + " where request_no = " + requestNo;
                    jdbcTemplate.update(sql1);
                }
            }
        }
    }

    /**
     * 查询通道提现状态接口
     * @param requestNo
     * @param merchantNo
     * @return
     * @throws ServiceException
     */
    @Transactional
    public void queryWithdraw(String requestNo,String merchantNo) throws ServiceException {
        FreeQuickRequest request = new FreeQuickRequest(CommonConstants.AGENT_NO, CommonConstants.AGENT_KEY);
        request.setSupportSign(false);
        request.setEncryptType(EncryptTypeEnum.AES);
        request.addParam("withdrawRequestNo", requestNo);//请求流水号
        request.addParam("merchantNo", merchantNo);//商户编号
        log.info("response:" + request.toString());

        FreeQuickResponse response = FreeQuickClient.post(CommonConstants.BASEURL+ CommonConstants.BASEURL_QUERY_WITHDRAW, request);
        log.info("response:" + JSON.toJSONString(response));
        Map<String, String> resp;
        if (response == null || (resp = response.getResultMap()) == null) {
            resp = ImmutableMap.of();
        }
        String bizCode = resp.getOrDefault("bizCode", "0");
        String codes = resp.getOrDefault("code", "0");
        String status = resp.getOrDefault("remitStatus", "0");

        //提现是否成功
        if(codes.equals(CommonConstants.FREE_SUCCESS)){
            if(bizCode.equals("1")){
                if(StringUtils.isNotBlank(status)){
                    String payStatus = CommonsUtil.queryStatus(status);
                    //更新交易状态
                    String sql = "update t_withdraw_order set pay_status = " + payStatus + " where request_no = " + requestNo;
                    jdbcTemplate.update(sql);
                    //更新提现临时任务
                    String sql1 = "UPDATE t_withdraw_temporary set pay_status = " + payStatus + " where request_no = " + requestNo;
                    jdbcTemplate.update(sql1);
                }
            }
        }
    }

    /**
     * 提现/代还
     * @param freeQuickWithdraw
     * @return
     * @throws Exception
     */
    @Transactional
    public Map<String,Object> withdraw(FreeQuickWithdraw freeQuickWithdraw) throws ServiceException {
        Map<String,Object> map = verifyMerchant(freeQuickWithdraw.getUserId(),freeQuickWithdraw.getChannelCode(),"1");
        Map<String,Object> result = (Map<String, Object>)map.getOrDefault("result","0");
        Map<String,Object> pram = (Map<String, Object>) result.getOrDefault("register","0");
        Map<String,Object> channelRate = (Map<String, Object>)result.getOrDefault("channelRate","0");
        Map<String, Object> resp = new HashMap<>();
        if(pram.size() > 0){
            BigDecimal extra = new BigDecimal(String.valueOf(channelRate.getOrDefault("extraFee","0")));
            int ex = extra.compareTo(BigDecimal.ZERO);
            if (ex == -1) {
                extra = new BigDecimal("2");
            }
            BigDecimal amount = new BigDecimal(freeQuickWithdraw.getAmount());
            if(StringUtils.isNotBlank(freeQuickWithdraw.getXfSt()) && freeQuickWithdraw.getXfSt().equals("0")){
                amount = new BigDecimal(freeQuickWithdraw.getAmount());
            }else{
                amount = amount.add(extra);
            }

            FreeQuickRequest request = freeQuickWithdraw.transform(pram);
            request.addParam("amount", String.valueOf(amount));
            request.addParam("serverCallbackUrl", CommonConstants.BASEURL_XJF + CommonConstants.BASEURL_WITHDRAW_BACK);//提现回调地址
            if(StringUtils.isBlank(freeQuickWithdraw.getXfType())){
                freeQuickWithdraw.setXfType(CommonConstants.TODAY);
            }
            request.addParam("walletType",freeQuickWithdraw.getXfType());

            log.info("畅捷出款上送参数request:" + request.toString());
            FreeQuickResponse response = FreeQuickClient.post(CommonConstants.BASEURL_WITHDRAW, request);
            log.info("上送畅捷出款响应参数response:" + JSON.toJSONString(response));
            resp = (Map) response.getResultMap();
            String bizCode = (String)resp.getOrDefault("bizCode", "0");
            String codes = (String)resp.getOrDefault("code", "0");
            //提现/代还是否成功
            if(codes.equals(CommonConstants.FREE_SUCCESS)){
                if(!bizCode.equals("1")){
                    if (log.isDebugEnabled()) {
                        log.debug("withdraw pay {},in params:{}" + freeQuickWithdraw.toString());
                    }
                    throw new RuntimeException(CommonsUtil.freeQuickError(bizCode));
                }else{
                    freeQuickWithdraw.setPayStatus("1");
                }
            }
            freeQuickWithdraw.setCode(response.getCode());
            freeQuickWithdraw.setBizMsg(response.getMessage());
            freeQuickWithdraw.setCreateTime(new Date());
            //保存提现/代还信息
            freeQuickWithdrawRepository.save(freeQuickWithdraw);
        }else {
            if (log.isDebugEnabled()) {
                log.debug("pay callback: {}, in params: {}", freeQuickWithdraw.toString());
                throw new ServiceException("该用户没有费率或银行卡信息");
            }
        }

        return resp;
    }

    /**
     * 查询use模块银行卡信息和推荐人汇率信息
     * @param cardNo
     *
     */
    public Map verifyBankInfo(String cardNo,String userId,String channelId,String payType){
        RestTemplate restTemplate = new RestTemplate();
        URI uri = util.getServiceUrl("user", "error url request");
        String url = uri.toString() + "/v1.0/user/freeQtuick/gradeRate";
        LinkedMultiValueMap<String,String> requestEntity = new LinkedMultiValueMap<String,String>();
        requestEntity.add("cardNo", cardNo);
        requestEntity.add("userId", userId);
        requestEntity.add("payType", payType);
        requestEntity.add("channelId", channelId);
        String resultString = restTemplate.postForObject(url, requestEntity, String.class);
        Map map = JSONObject.fromObject(resultString);
        return map;
    }

    public Map<String,Object> verifyMerchant(String userId,String channelId,String payType){
        RestTemplate restTemplate = new RestTemplate();
        URI uri = util.getServiceUrl("user", "error url request");
        String url = uri.toString() + "/v1.0/user/freeQtuick/merchant";
        LinkedMultiValueMap<String,String> requestEntity = new LinkedMultiValueMap<String,String>();
        requestEntity.add("userId", userId);
        requestEntity.add("payType",payType);
        requestEntity.add("channelProductCode", channelId);
        String resultString = restTemplate.postForObject(url, requestEntity, String.class);
        Map<String,Object> map = JSONObject.fromObject(resultString);
        return map;
    }

    public Map<String,String> queryLogin(String phone){
        RestTemplate restTemplate = new RestTemplate();
        URI uri = util.getServiceUrl("user", "error url request");
        String url = uri.toString() + "/v1.0/user/freeQtuick/query/login";
        LinkedMultiValueMap<String,String> requestEntity = new LinkedMultiValueMap<String,String>();
        requestEntity.add("phone", phone);
        String resultString = restTemplate.postForObject(url, requestEntity, String.class);
        Map<String,String> map = JSONObject.fromObject(resultString);
        return map;
    }


    public Map verifyBankInfo(String cardNo){
        RestTemplate restTemplate = new RestTemplate();
        URI uri = util.getServiceUrl("user", "error url request");
        String url = uri.toString() + "/v1.0/user/freeQtuick/queryBankInfo";
        LinkedMultiValueMap<String,String> requestEntity = new LinkedMultiValueMap<String,String>();
        requestEntity.add("cardNo", cardNo);
        String resultString = restTemplate.postForObject(url, requestEntity, String.class);
        Map map = JSONObject.fromObject(resultString);
        return map;
    }

    public Map verifyUserAccount(String userId,String rebateBalance){
        RestTemplate restTemplate = new RestTemplate();
        URI uri = util.getServiceUrl("user", "error url request");
        String url = uri.toString() + "/v1.0/user/freeQtuick/saveAccount";
        LinkedMultiValueMap<String,String> requestEntity = new LinkedMultiValueMap<String,String>();
        requestEntity.add("rebateBalance", rebateBalance);
        requestEntity.add("userId", userId);
        String resultString = restTemplate.postForObject(url, requestEntity, String.class);
        Map map = JSONObject.fromObject(resultString);
        return map;
    }



    /**
     * 提现/代还查询
     * @param entity
     * @return map
     * @throws ServiceException
     */
    public Map querywithdraw(FreeQuickWithdraw entity) throws ServiceException {
        FreeQuickRequest request = new FreeQuickRequest(CommonConstants.AGENT_NO, CommonConstants.AGENT_KEY);
        request.setSupportSign(false);
        request.setEncryptType(EncryptTypeEnum.AES);
        request.addParam("withdrawRequestNo", entity.getWithdrawRequestNo());//提现流水号
        request.addParam("merchantNo", CommonConstants.AGENT_NO);//商户编号
        log.info("response:" + request.toString());
        FreeQuickResponse response = FreeQuickClient.post(CommonConstants.BASEURL_QUERY_WITHDRAW, request);
        log.info("response:" + JSON.toJSONString(response));
        Map<String, String> resp = response.getResultMap();
        String bizCode = resp.getOrDefault("bizCode", "0");
        Map<String, String> map = new HashMap<>();
        //查询成功
        if(resp.getOrDefault("code", "").equalsIgnoreCase("200")){
            if(!bizCode.equals("1")){
                map.put("msg",CommonsUtil.freeQuickError(bizCode));
                map.put("code","0");
                map.put("success",response.getMessage());
            }else{
                map = response.getResultMap();
                map.put("code","1");
                map.put("success",response.getMessage());
            }
        }
        return map;
    }

    /**
     * 交易查询
     * @return map
     * @throws ServiceException
     */
    public Map querypayment(FreeQuickOrder freeQuickOrder) throws ServiceException {
        FreeQuickRequest request = new FreeQuickRequest(CommonConstants.AGENT_NO, CommonConstants.AGENT_KEY);
        request.setSupportSign(false);
        request.setEncryptType(EncryptTypeEnum.AES);
        request.addParam("requestNo", freeQuickOrder.getRequestNo());//交易流水号
        request.addParam("merchantNo", CommonConstants.AGENT_NO);//商户编号
        log.info("response:" + request.toString());
        FreeQuickResponse response = FreeQuickClient.post(CommonConstants.BASEURL + CommonConstants.BASEURL_PAYM, request);
        log.info("response:" + JSON.toJSONString(response));
        Map<String, String> resp = response.getResultMap();
        String bizCode = resp.getOrDefault("bizCode", "0");
        Map<String, String> map = new HashMap<>();
        //查询成功
        if(resp.getOrDefault("code", "").equalsIgnoreCase("200")){
            if(!bizCode.equals("1")){
                map.put("msg",CommonsUtil.freeQuickError(bizCode));
                map.put("code","0");
            }else{
                map = response.getResultMap();
                map.put("code","1");
            }
        }
        return map;
    }

    /**
     * 余额提现
     * @param entity
     * @param balance 余额
     * @param bankCard 银行卡
     * @param rate 提现费率
     * @param extraFee 提现手续费
     * @return
     */
    @Transactional
    @Override
    public Map<String, Object> balanceWithdraw(FreeQuickWithdraw entity, BigDecimal balance, String bankCard, BigDecimal rate, BigDecimal extraFee) throws ServiceException {
        Map<String, Object> resMap = new HashMap<>();
        /* 提现流水号 */
        Random rand = new Random();
        int randNum = rand.nextInt(9999)+10000;
        String orderCode = DateUtil.getyyyyMMddHHmmssSSSDateFormat(Calendar.getInstance().getTime()) + randNum;
        entity.setWithdrawRequestNo(orderCode);
        entity.setRequestNo(orderCode);
        /* 1、计算提现后余额、实际提现金额 */
        /* 提现计算费率接口公式例如：2.74=(300*0.0058) +1 */
        String amountStr = StringUtils.trimToEmpty(entity.getAmount());//提现金额
        if (isEmpty(amountStr)) {
            log.info("提现金额为空！userId = " + entity.getUserId());
            throw new ServiceException("提现金额为空！");
        }
        BigDecimal amount = new BigDecimal(amountStr);//要提现金额
        balance = balance.subtract(amount);
        /* 提现总手续费 */
        BigDecimal totalFee = amount.multiply(rate).add(extraFee);
        totalFee = totalFee.setScale(2, BigDecimal.ROUND_UP);

        /* 实际提现金额 = 要提现金额 - 提现总手续费 */
        BigDecimal actualAmount = amount.subtract(totalFee);
        entity.setAmount(actualAmount.toString());
        entity.setPayType("3");
        /* 2、连接通道提现 */
        Map<String, Object> withdrawMap = withdraw(entity);

        log.info("连接通道进行余额提现返回结果 withdrawMap = " + withdrawMap.toString());

        String code = withdrawMap.getOrDefault("code","1").toString();
        String msg = withdrawMap.getOrDefault("msg","1").toString();

        log.info("连接通道进行余额提现返回code和msg信息 code = " + code + "（code = 0异常，code = 1无异常）；msg = " + msg);

        if(code.equals("0")){
            //提现异常
            throw new ServiceException(msg);
        }

        /* 3、更新用户账户信息表 */
        URI uri = util.getServiceUrl("user", "error url request!");
        String url = uri.toString() + "/v1.0/user/userAccount/updateAccount";

        MultiValueMap<String, Object> requestEntity = new LinkedMultiValueMap<>();
        requestEntity.add("userId", entity.getUserId());
        requestEntity.add("amount", amount);//用户提现金额
        requestEntity.add("actualAmount", actualAmount);//用户实际提现金额
        requestEntity.add("balance", balance);
        requestEntity.add("bankCard", bankCard);
        requestEntity.add("orderCode", orderCode);//提现订单
        requestEntity.add("addorsub", "1");//0加1减（0充值，1提现）

        RestTemplate restTemplate = new RestTemplate();
        String result = restTemplate.postForObject(url, requestEntity, String.class);

        log.info("余额提现更新用户账户信息返回结果result = " + result);

        JSONObject jsonObject = JSONObject.fromObject(result);
        Object resp_code = jsonObject.get("resp_code");
        if (CommonConstants.SUCCESS.equals(resp_code)) {
            //提现成功
            resMap.putAll(jsonObject);
            return resMap;
        } else {
            Map<String, Object> map = new HashMap();
            map.put(CommonConstants.RESP_CODE, CommonConstants.FALIED);
            map.put(CommonConstants.RESULT, "");
            map.put(CommonConstants.RESP_MESSAGE, "提现失败");
            return map;
        }
    }

    @Transactional
    public void processPayNotify(FreeQuickOrder freeQuickOrder) throws PayBarException {
        FreeQuickOrder order = freeQuickOrderRepository.findFreeQuickOrderByMerchantNoAndRAndRequestNo(freeQuickOrder.getRequestNo(), freeQuickOrder.getMerchantNo());
        if (order == null) {
            throw new PayBarException("支付订单信息不存在，商户号[" + freeQuickOrder.getMerchantNo() + "]请求单号[" + freeQuickOrder.getRequestNo() + "]");
        }
        if (order.getAmount().compareTo(freeQuickOrder.getAmount()) != 0) {
            throw new PayBarException("支付订单[" + freeQuickOrder.getRequestNo() + "]金额返回异常，金额:" + freeQuickOrder.getAmount());
        }
        String orderStatus = order.getPayStatus();
        if (!orderStatus.equals("1")) {
            throw new PayBarException("订单[" + order.getMerchantNo() + "]已经支付" + order.getBizMsg());
        }
        ;
        // 支付状态若为成功，更新分润信息，更新用户交易状态
        if (orderStatus.equals("1") && freeQuickOrder.getFeeStatus() == 1) {
            Map maps = checkAccount(order.getUserId(), order.getGradeAmount());
            String code = (String) maps.getOrDefault("","0");
            if(code.equals(CommonConstants.SUCCESS)){
                log.info("更新分润信息成功");
            }
            order.setPayStatus("1");
        }else{
            order.setPayStatus("2");
        }
        freeQuickOrderRepository.save(order);
    }

    @Transactional
    public void processPaywithdraw(FreeQuickWithdraw freeQuickWithdraw) throws PayBarException {
        FreeQuickWithdraw order = freeQuickWithdrawRepository.findFreeQuickWithdrawPageByMerchantNoAndRAndRequestNo(freeQuickWithdraw.getRequestNo(), freeQuickWithdraw.getMerchantNo());
        if (order == null) {
            throw new PayBarException("支付订单信息不存在，商户号[" + freeQuickWithdraw.getMerchantNo() + "]请求单号[" + freeQuickWithdraw.getRequestNo() + "]");
        }
        if (order.getAmount().compareTo(freeQuickWithdraw.getAmount()) != 0) {
            throw new PayBarException("支付订单[" + freeQuickWithdraw.getRequestNo() + "]金额返回异常，金额:" + freeQuickWithdraw.getAmount());
        }
        String orderStatus = order.getPayStatus();
        if (!orderStatus.equals("1")) {
            throw new PayBarException("订单[" + order.getMerchantNo() + "]已经支付" + order.getBizMsg());
        }
        ;
        // 支付状态若为成功，更新分润信息，更新用户交易状态
        if (orderStatus.equals("1") && freeQuickWithdraw.getFeeStatus() == 1) {
            Map maps = checkAccount(order.getUserId(), order.getGradeAmount());
            String code = (String) maps.getOrDefault("","0");
            if(code.equals(CommonConstants.SUCCESS)){
                log.info("更新分润信息成功");
            }
            order.setPayStatus("1");
        }else{
            order.setPayStatus("2");
        }
        freeQuickWithdrawRepository.save(freeQuickWithdraw);
    }

    @Override
    public BigDecimal getTodayIncome(String userId) throws ServiceException {
        Date currentTime = Calendar.getInstance().getTime();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String formatDate = sdf.format(currentTime);
        BigDecimal todayIncome = freeQuickWithdrawRepository.getTodayIncome(userId, formatDate);
        if (todayIncome == null) {
            return new BigDecimal("0.00");
        }
        return todayIncome;
    }

    private Specification<FreeQuickOrder> whereFqo (final String startTime, final String endTime, final String requestNo, final String merchantNo,
                                                 final String channelProductCode, final String bankCardNo, final String productName, final String channelType,
                                                 final String payStatus, final String userId, final String payType) {
        return (root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (isNotBlank(startTime)) {
                String startTime_new = startTime + " 00:00:00";
                predicates.add(criteriaBuilder.greaterThan(root.<Date>get("createTime"), DateUtil.getYYMMHHMMSSDateFromStr(startTime_new)));
            }
            if (isNotBlank(endTime)) {
                String endTime_new = endTime + " 23:59:59";
                predicates.add(criteriaBuilder.lessThan(root.<Date>get("createTime"), DateUtil.getYYMMHHMMSSDateFromStr(endTime_new)));
            }
            if (isNotBlank(requestNo)) {
                predicates.add(criteriaBuilder.equal(root.<String>get("requestNo"), requestNo));
            }
            if (isNotBlank(merchantNo)) {
                predicates.add(criteriaBuilder.equal(root.<String>get("merchantNo"), merchantNo));
            }
            if (isNotBlank(channelProductCode)) {
                predicates.add(criteriaBuilder.equal(root.<String>get("channelProductCode"), channelProductCode));
            }
            if (isNotBlank(bankCardNo)) {
                predicates.add(criteriaBuilder.equal(root.<String>get("bankCardNo"), bankCardNo));
            }
            if (isNotBlank(productName)) {
                predicates.add(criteriaBuilder.equal(root.<String>get("productName"), productName));
            }
            if (isNotBlank(channelType)) {
                predicates.add(criteriaBuilder.equal(root.<String>get("channelType"), channelType));
            }
            if (isNotBlank(payStatus)) {
                predicates.add(criteriaBuilder.equal(root.<String>get("payStatus"), payStatus));
            }
            if (isNotBlank(userId)) {
                predicates.add(criteriaBuilder.equal(root.<String>get("userId"), userId));
            }
            if (isNotBlank(payType)) {
                predicates.add(criteriaBuilder.equal(root.<String>get("payType"), payType));
            }
            return criteriaQuery.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
        };
    }

    @Override
    public Page<FreeQuickOrder> findPassagewayOrderPage(String startTime, String endTime, String requestNo, String merchantNo, String channelProductCode,
                                                        String bankCardNo, String productName, String channelType, String payStatus, String userId,
                                                        String payType, Pageable pageable) throws ServiceException {
        return freeQuickOrderRepository.findAll(whereFqo(startTime, endTime, requestNo, merchantNo,
        channelProductCode, bankCardNo, productName, channelType, payStatus, userId, payType), pageable);
    }


    private Specification<FreeQuickWithdraw> whereFqw(final String userId, final String requestNo, final String merchantNo, final String channelCode,
                                                      final String bankAccountNo, final String bankAccountName, final String bankAccountType, final String bankName,
                                                      final String bankSubName, final String bankProvince, final String bankCity, final String withdrawRequestNo,
                                                      final String payType, final String channelType, final String payStatus, final String startTime, final String endTime) {
        return (root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (isNotBlank(userId)) {
                predicates.add(criteriaBuilder.equal(root.<String>get("userId"), userId));
            }
            if (isNotBlank(requestNo)) {
                predicates.add(criteriaBuilder.equal(root.<String>get("requestNo"), requestNo));
            }
            if (isNotBlank(merchantNo)) {
                predicates.add(criteriaBuilder.equal(root.<String>get("merchantNo"), merchantNo));
            }
            if (isNotBlank(channelCode)) {
                predicates.add(criteriaBuilder.equal(root.<String>get("channelCode"), channelCode));
            }
            if (isNotBlank(bankAccountNo)) {
                predicates.add(criteriaBuilder.equal(root.<String>get("bankAccountNo"), bankAccountNo));
            }
            if (isNotBlank(bankAccountName)) {
                predicates.add(criteriaBuilder.equal(root.<String>get("bankAccountName"), bankAccountName));
            }
            if (isNotBlank(bankAccountType)) {
                predicates.add(criteriaBuilder.equal(root.<String>get("bankAccountType"), bankAccountType));
            }
            if (isNotBlank(bankName)) {
                predicates.add(criteriaBuilder.equal(root.<String>get("bankName"), bankName));
            }
            if (isNotBlank(bankSubName)) {
                predicates.add(criteriaBuilder.equal(root.<String>get("bankSubName"), bankSubName));
            }
            if (isNotBlank(bankProvince)) {
                predicates.add(criteriaBuilder.equal(root.<String>get("bankProvince"), bankProvince));
            }
            if (isNotBlank(bankCity)) {
                predicates.add(criteriaBuilder.equal(root.<String>get("bankCity"), bankCity));
            }
            if (isNotBlank(withdrawRequestNo)) {
                predicates.add(criteriaBuilder.equal(root.<String>get("withdrawRequestNo"), withdrawRequestNo));
            }
            if (isNotBlank(payType)) {
                predicates.add(criteriaBuilder.equal(root.<String>get("payType"), payType));
            }
            if (isNotBlank(channelType)) {
                predicates.add(criteriaBuilder.equal(root.<String>get("channelType"), channelType));
            }
            if (isNotBlank(payStatus)) {
                predicates.add(criteriaBuilder.equal(root.<String>get("payStatus"), payStatus));
            }
            if (isNotBlank(startTime)) {
                String startTime_new = startTime+" 23:59:59";
                predicates.add(criteriaBuilder.greaterThan(root.<Date>get("createTime"), DateUtil.getYYMMHHMMSSDateFromStr(startTime_new)));
            }
            if (isNotBlank(endTime)) {
                String endTime_new = endTime+" 23:59:59";
                predicates.add(criteriaBuilder.lessThan(root.<Date>get("createTime"), DateUtil.getYYMMHHMMSSDateFromStr(endTime_new)));
            }

            return criteriaQuery.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
        };
    }

    @Override
    public Page<FreeQuickWithdraw> findFreeQuickWithdrawPage(String userId, String requestNo, String merchantNo, String channelCode, String bankAccountNo,
                                                             String bankAccountName, String bankAccountType, String bankName, String bankSubName, String bankProvince,
                                                             String bankCity, String withdrawRequestNo, String payType, String channelType, String payStatus,
                                                             String startTime, String endTime, Pageable pageable) {
        return freeQuickWithdrawRepository.findAll(whereFqw(userId, requestNo, merchantNo, channelCode, bankAccountNo,
                bankAccountName, bankAccountType, bankName, bankSubName, bankProvince,
                bankCity, withdrawRequestNo, payType, channelType, payStatus,
                startTime, endTime), pageable);
    }

    /**
     * 更新分润信息
     * @param userId
     * @param amount
     * @return
     */
    private Map<String, Object> checkAccount(String userId, BigDecimal amount) {
        Map<String, Object> resMap = new HashMap<>();
        RestTemplate restTemplate = new RestTemplate();
        URI uri = util.getServiceUrl("user", "error url request");
        String url = uri.toString() + "/v1.0/user/userAccount/addAccount";
        LinkedMultiValueMap<String, String> requestEntity = new LinkedMultiValueMap<String, String>();
        requestEntity.add("userId", userId);
        requestEntity.add("amount", amount+"");
        String result = restTemplate.postForObject(url, requestEntity, String.class);
        resMap = JSONObject.fromObject(result);
        return resMap;
    }

    @Override
    @Transactional
    public void queryAndUpdateFreeQuickOrderJob() throws ServiceException {
        /* 1、获取所有处在支付中的交易记录，并更新交易记录表状态 */
        //new Thread(new queryAndUpdateFreeQuickOrderJob(), "Thread-获取所有处在支付中的交易记录，并更新交易记录表状态").start();
        /* 2、获取所有处在支付中的代还/提现记录，并更新代还/提现记录表状态 */
        //new Thread(new queryAndUpdateFreeQuickWithdrawJob(), "Thread-获取所有处在支付中的代还/提现记录，并更新代还/提现记录表状态").start();

        /* 1、获取所有处在支付中的交易记录，并更新交易记录表状态 */
        List<FreeQuickOrder> freeQuickOrderList = freeQuickOrderRepository.getAllInProcess();
        if (freeQuickOrderList != null && freeQuickOrderList.size() > 0) {
            for (FreeQuickOrder freeQuickOrder : freeQuickOrderList) {
                String requestNo = freeQuickOrder.getRequestNo();//请求流水号
                if (isEmpty(requestNo)) {
                    continue;
                }
                Map<String, Object> orderResult = querypayment(freeQuickOrder);
                String code = orderResult.getOrDefault("code", "0").toString();
                String status = orderResult.getOrDefault("status", "PROCESS").toString();//默认状态：支付中
                String isSuccess = orderResult.getOrDefault("success", "false").toString();
                String resultStatus = CommonsUtil.getResultStatus(status);
                if (Objects.equals("false", isSuccess)) {
                    resultStatus = "2";
                }

                if (Objects.equals("0", code)) {
                    //失败
                    String msg = orderResult.getOrDefault("msg", "").toString();
                    if (msg.contains("异常")) {
                        resultStatus = "3";
                    }
                    //更新交易记录状态
                    int updateResult = freeQuickOrderRepository.updateByRequestNo(resultStatus, requestNo);
                    log.info("更新t_passageway_order交易记录状态 updateResult = " + updateResult + "（1：更新成功，0：更新失败）请求流水号requestNo = " + requestNo);
                }
                if ("1".equals(code)) {
                    //查询结果未抛出异常， 查询是否成功
                    if (!PAYMENT_STATUS_PROCESS.equals(resultStatus)) {
                        //更新交易记录状态
                        int updateResult = freeQuickOrderRepository.updateByRequestNo(resultStatus, requestNo);
                        log.info("更新t_passageway_order交易记录状态 updateResult = " + updateResult + "（1：更新成功，0：更新失败）请求流水号requestNo = " + requestNo);
                    }
                }
            }
        }
    }

    @Override
    @Transactional
    public void queryAndUpdateFreeQuickWithdrawJob() throws ServiceException {
        /* 2、获取所有处在支付中的代还/提现记录，并更新代还/提现记录表状态 */
        List<FreeQuickWithdraw> freeQuickWithdrawList = freeQuickWithdrawRepository.getAllInProcess();
        if (freeQuickWithdrawList.size() > 0) {
            for (FreeQuickWithdraw freeQuickWithdraw: freeQuickWithdrawList) {
                String withdrawRequestNo = freeQuickWithdraw.getWithdrawRequestNo();//请求流水号
                if (isEmpty(withdrawRequestNo)) {
                    continue;
                }
                Map<String, Object> withdrawResult = querywithdraw(freeQuickWithdraw);
                log.info("获取所有处在支付中的代还/提现记录，并更新代还/提现记录表状态withdrawResult = " + withdrawResult.toString());
                String code = withdrawResult.getOrDefault("code", "0").toString();
                String isSuccess = withdrawResult.getOrDefault("success", "false").toString();
                String status = withdrawResult.getOrDefault("status", "PROCESS").toString();//默认状态：支付中
                String resultStatus = CommonsUtil.getResultStatus(status);
                if ("false".equals(isSuccess)) {
                    resultStatus = CommonConstants.PAYMENT_STATUS_FAILURE;
                }

                if ("0".equals(code)) {
                    //提现失败
                    String respCode = getRespCode(freeQuickWithdraw, withdrawRequestNo);
                    if (!CommonConstants.SUCCESS.equals(respCode)) {
                        //throw new ServiceException("退款失败！");
                        continue;
                    }
                    //更新代还/提现记录表状态
                    int updateResult = freeQuickWithdrawRepository.updateByRequestNo(resultStatus, withdrawRequestNo);
                    log.info("更新t_withdraw_order交易记录状态 updateResult = " + updateResult + "（1：更新成功，0：更新失败）请求流水号withdrawRequestNo = " + withdrawRequestNo);
                } else if ("1".equals(code)) {
                    //查询结果未抛出异常，判断是否提现成功
                    if (!PAYMENT_STATUS_PROCESS.equals(resultStatus)) {
                        if ("false".equals(isSuccess) && "3".equals(freeQuickWithdraw.getPayType())) {
                            //支付失败且为余额提现，退款
                            String respCode = getRespCode(freeQuickWithdraw, withdrawRequestNo);
                            if (!CommonConstants.SUCCESS.equals(respCode)) {
                                //throw new ServiceException("退款失败！");
                                continue;
                            }
                        }
                        //更新代还/提现记录表状态
                        int updateResult = freeQuickWithdrawRepository.updateByRequestNo(resultStatus, withdrawRequestNo);
                        log.info("更新t_withdraw_order交易记录状态 updateResult = " + updateResult + "（1：更新成功，0：更新失败）请求流水号withdrawRequestNo = " + withdrawRequestNo);
                    }
                }
            }
        }
    }


    private String getRespCode(FreeQuickWithdraw freeQuickWithdraw, String withdrawRequestNo) {
        /* 1、获取请求模块地址 */
        URI uri = util.getServiceUrl("user", "error url request!");
        String url = uri + "/v1.0/user/userAccount/refundBalannce";

        /* 2、封装请求参数 */
        MultiValueMap<String, Object> requestEntity = new LinkedMultiValueMap<>();
        requestEntity.add("userId", freeQuickWithdraw.getUserId());
        requestEntity.add("orderCode", withdrawRequestNo);

        /* 3、创建连接 */
        RestTemplate restTemplate = new RestTemplate();
        String result = restTemplate.postForObject(url, requestEntity, String.class);

        log.info("访问user模块退款操作返回结果 result = " + result);

        /* 4、处理返回结果 */
        JSONObject jsonObject = JSONObject.fromObject(result);
        return jsonObject.get("resp_code").toString();
    }

    @Override
    public Page<FreeQuickWithdraw> rechargePage(String userId, String status, Pageable pageable) throws ServiceException {
        if (isEmpty(status)) {
            return freeQuickWithdrawRepository.rechargePageNotStatus(userId, pageable);
        } else {
            return freeQuickWithdrawRepository.rechargePage(userId, status, pageable);
        }
    }


    /**
     * 代还
     * @param freeQuickWithdraw
     * @return
     * @throws ServiceException
     */
    @Transactional
    public Map taskWithdraw(FreeQuickWithdraw freeQuickWithdraw) throws ServiceException {
        Map<String,Object> map = new HashMap();
        map = verifyBankInfo(freeQuickWithdraw.getBankAccountNo());

        FreeQuickRequest request = new FreeQuickRequest(CommonConstants.AGENT_NO, CommonConstants.AGENT_KEY);
        Map<String,Object> result = (Map)map.getOrDefault("result","0");
        String requestNo = String.valueOf(System.currentTimeMillis());
        if(result.size() > 0){
            freeQuickWithdraw.setBankCode((String) result.getOrDefault("city", "0"));
                freeQuickWithdraw.setBankArea((String) result.getOrDefault("city", "0"));
                freeQuickWithdraw.setBankCity((String) result.getOrDefault("city","0" ));
                freeQuickWithdraw.setBankProvince((String) result.getOrDefault("province", "0"));
                freeQuickWithdraw.setBankAbbr((String)result.getOrDefault("bankAbbr","0" ));
                freeQuickWithdraw.setBankCode((String) result.getOrDefault("abbReviation","0" ));
                freeQuickWithdraw.setBankChannelNo((String) result.getOrDefault("lineNo", "0"));
                freeQuickWithdraw.setBankSubName((String) result.getOrDefault("bankBranchName","0" ));
                freeQuickWithdraw.setBankName((String) result.getOrDefault("bankName","0" ));
                freeQuickWithdraw.setBankAccountName((String) result.getOrDefault("userName", "0"));
                freeQuickWithdraw.setBankAccountNo((String) result.getOrDefault("cardNo", "0"));

        }
        freeQuickWithdraw.setRequestNo(requestNo);
        Map pram = verifyMerchant(freeQuickWithdraw.getUserId(),freeQuickWithdraw.getChannelCode(),"2");
        Map resul = (Map)pram.getOrDefault("result","0");
        Map channelRate = (Map)resul.getOrDefault("channelRate","0");
        //提现中
        freeQuickWithdraw.setPayStatus("4");
        int extraFee = (Integer)channelRate.getOrDefault("extraFee","0");
        BigDecimal extra = new BigDecimal(extraFee);
        BigDecimal amount = new BigDecimal(freeQuickWithdraw.getAmount());
        amount = amount.add(extra);
        request.setSupportSign(false);
        request.setEncryptType(EncryptTypeEnum.AES);
        request.addParam("requestNo", requestNo);//请求流水号
        request.addParam("merchantNo", freeQuickWithdraw.getMerchantNo());//商户编号
        request.addParam("channelCode", "CHANPAYNEWCARD");//渠道编码
        request.addParam("bankAccountNo", freeQuickWithdraw.getBankAccountNo());//银行账号
        request.addParam("bankAccountName", freeQuickWithdraw.getBankAccountName());//银行账户名
        request.addParam("bankAccountType", CommonConstants.PRIVATE);//账户类型
        request.addParam("bankName", freeQuickWithdraw.getBankAccountName());//银行名称
        request.addParam("bankSubName", freeQuickWithdraw.getBankSubName());//支行名称
        request.addParam("bankChannelNo", freeQuickWithdraw.getBankChannelNo());// 银行行联号
        request.addParam("bankCode", freeQuickWithdraw.getBankCode());//银行代码
        request.addParam("bankAbbr", freeQuickWithdraw.getBankAbbr());//银行代号
        request.addParam("bankProvince", freeQuickWithdraw.getBankProvince());//银行所属省
        request.addParam("bankCity", freeQuickWithdraw.getBankCity());//银行所属市
        request.addParam("bankArea", freeQuickWithdraw.getBankArea());//银行所属区域
        request.addParam("walletType", CommonConstants.TODAY);//钱包类型
        request.addParam("amount", String.valueOf(amount));//提现金额提现时把提现手续费加入，因为交易时候扣除了交易手续费，在用户提现时商户需要获得提现，到账记录必须是完整；
        request.addParam("serverCallbackUrl", CommonConstants.BASEURL_XJF + CommonConstants.BASEURL_WITHDRAW_BACK);//提现回调地址

        log.info("response:" + request.toString());
        FreeQuickResponse response = FreeQuickClient.post(CommonConstants.BASEURL_WITHDRAW,request);
        log.info("response:" + JSON.toJSONString(response));
        Map<String, String> resp = response.getResultMap();
        String bizCode = resp.getOrDefault("bizCode", "0");
        String codes = resp.getOrDefault("code", "0");
        String status = resp.getOrDefault("status", "0");
        resp.put("code", codes);
        //提现是否成功
        if(codes.equals(CommonConstants.FREE_SUCCESS)){
            if(!bizCode.equals("1") || !status.toUpperCase().equals(CommonConstants.BASE_SUCCESS.toUpperCase())){
                String bizMsg = resp.getOrDefault("bizMsg", "0");
                resp.put("msg",bizMsg);
                resp.put("resp_code", bizCode);
            }else{
                freeQuickWithdraw.setPayStatus("4");
                freeQuickWithdraw.setPayStatus("1");
                resp.put("resp_code",CommonConstants.SUCCESS);
                resp.put("msg",CommonConstants.BASE_SUCCESS);
            }
        }
        freeQuickWithdraw.setPayType("2");
        freeQuickWithdraw.setCode(response.getCode());
        freeQuickWithdraw.setBizMsg(response.getMessage());
        freeQuickWithdraw.setCreateTime(new Date());
        //保存提现/代还信息
        freeQuickWithdrawRepository.save(freeQuickWithdraw);
        return resp;
    }

    @Override
    @Transactional
    public Map<String, Object> queryWithDraw(String merchantNo, String requestNo) throws ServiceException {
        Map<String, Object> resMap = new HashMap<>();
        resMap.put("merchantNo", merchantNo);
        resMap.put("requestNo", requestNo);

        // 1、获取畅捷通道中的商户编号
        merchantNo = getMerchantNo(merchantNo);
        // 2、调用查询提现结果接口
        Map<String, String> res = FreeQuickProxyService.queryWithDraw(merchantNo, requestNo);
        log.info("调用查询提现结果接口响应res = {}", res);
        // 3、处理返回结果
        if (null == res) {
            throw new ServiceException("查询商户提现结果信息失败，请稍后再试！");
        }

        String bizCode = res.get("bizCode");
        String code = res.get("code");
        String bizMsg = res.get("bizMsg");
        if (!"1".equals(bizCode) || !"200".equals(code)) {
            // 失败
            log.info("查询商户提现结果信息失败：畅捷商户编号merchantNo = {}，请求流水号requestNo = {}，接口返回：bizCode={}，bizMsg={}", merchantNo, requestNo, bizCode, bizMsg);
            throw new ServiceException(bizMsg);
        }

        // 4、查询成功
        String amount = res.get("amount"); // 提现金额
        String remitStatus = res.get("remitStatus"); // 提现状态：INIT待确认，REMITING出款中，SUCCESS出款成功，FAIL出款失败，UNKNOW未知
        String withdrawDepositFee = res.get("withdrawDepositFee"); // 提现手续费

        resMap.put("amount", amount);
        resMap.put("remitStatus", remitStatus(remitStatus));
        resMap.put("withdrawDepositFee", withdrawDepositFee);

        // 5、更新畅捷代还/提现记录表t_withdraw_order
        FreeQuickWithdraw freeQuickWithdraw = freeQuickWithdrawRepository.getByMerchantNoAndRequestNo(merchantNo, requestNo);
        if (null == freeQuickWithdraw) {
            // TODO do other things
            return resMap;
        }
        String payStatus = freeQuickWithdraw.getPayStatus();
        if ("3".equals(payStatus) || "4".equals(payStatus)) {
            // 若订单状态为（3：异常,4：提现中），则更新状态
            if ("SUCCESS".equals(remitStatus)) {
                freeQuickWithdraw.setPayStatus("1"); // 成功
                freeQuickWithdrawRepository.save(freeQuickWithdraw);
            }
            if ("REMITING".equals(remitStatus)) {
                freeQuickWithdraw.setPayStatus("4"); // 提现中
                freeQuickWithdrawRepository.save(freeQuickWithdraw);
            }
            if ("UNKNOW".equals(remitStatus) || "FAIL".equals(remitStatus)) {
                freeQuickWithdraw.setPayStatus("0"); // 代提现
                freeQuickWithdrawRepository.save(freeQuickWithdraw);
            }
        }
        return resMap;
    }

    @Override
    public Map<String, Object> noCardRebatePage(String phone, String requestNo, String channelTag, String startTime, String endTime, Pageable pageable) throws ServiceException {
        Map<String, Object> resMap = new LinkedHashMap<>();
        List<Map<String, Object>> list = new ArrayList<>();

        if (StringUtils.isNotBlank(startTime) && StringUtils.isNotBlank(endTime) && startTime.length() == 10 && endTime.length() == 10) {
            startTime = startTime + " 00:00:00";
            endTime = endTime + " 23:59:59";
        }
        Page<FreeQuickOrder> freeQuickOrderPage = freeQuickOrderRepository.findAll(where(phone, requestNo, channelTag, startTime, endTime), pageable);
        List<FreeQuickOrder> content = freeQuickOrderPage.getContent();
        if (content.size() == 0) {
            resMap.put("content", content);
        } else {
            // 获取userId和brandUserId的手机号码
            StringBuilder preUserIdSb = new StringBuilder();
            StringBuilder brandUserIdSb = new StringBuilder();
            for (FreeQuickOrder order : freeQuickOrderPage) {
                if (StringUtils.isNotBlank(order.getPreUserId())) {
                    preUserIdSb.append(order.getPreUserId()).append(",");
                }
                if (StringUtils.isNotBlank(order.getBrandUserId())) {
                    brandUserIdSb.append(order.getBrandUserId()).append(",");
                }
            }

            JSONArray preUserArray = new JSONArray();
            if (preUserIdSb.length() > 0) {
                preUserArray = getUserPhone(preUserIdSb.substring(0, preUserIdSb.length() - 1));
            }
            JSONArray brandUserArray = new JSONArray();
            if (brandUserIdSb.length() > 0) {
                brandUserArray = getUserPhone(brandUserIdSb.substring(0, brandUserIdSb.length() - 1));
            }

            for (FreeQuickOrder order : freeQuickOrderPage) {
                Map<String, Object> map = new LinkedHashMap<>();
                requestNo = order.getRequestNo();
                String merchantNo = order.getMerchantNo();
                BigDecimal inAmount = order.getInAmount();
                String productName = order.getProductName();
                String preUserId = order.getPreUserId();
                String brandUserId = order.getBrandUserId();
                BigDecimal gradeAmount = order.getGradeAmount();
                BigDecimal brandAmount = order.getBrandAmount();
                String payType = order.getPayType();
                channelTag = order.getChannelTag();
                Date createTime = order.getCreateTime();

                map.put("requestNo", requestNo);
                map.put("merchantNo", merchantNo);
                map.put("inAmount", inAmount);
                map.put("productName", productName);
                map.put("preUserPhone", "");
                phoneMap(preUserArray, map, preUserId, "preUserPhone");
                map.put("gradeAmount", gradeAmount);
                map.put("brandUserPhone", "");
                phoneMap(brandUserArray, map, brandUserId, "brandUserPhone");
                map.put("brandAmount", brandAmount);
                map.put("payType", payType);
                map.put("channelTag", channelTag);
                map.put("createTime", createTime);

                list.add(map);
            }
            resMap.put("content", list);
        }

        resMap.put("first", freeQuickOrderPage.isFirst());
        resMap.put("last", freeQuickOrderPage.isLast());
        resMap.put("totalElements", freeQuickOrderPage.getTotalElements());
        resMap.put("totalPages", freeQuickOrderPage.getTotalPages());
        resMap.put("number", freeQuickOrderPage.getNumber());
        resMap.put("size", freeQuickOrderPage.getSize());
        resMap.put("sort", freeQuickOrderPage.getSort());
        resMap.put("numberOfElements", freeQuickOrderPage.getNumberOfElements());
        return resMap;
    }

    void phoneMap(JSONArray userArray, Map<String, Object> map, String userIdStr, String phoneKey) {
        if (userArray.size() > 0) {
            for (int i = 0; i < userArray.size(); i++) {
                JSONObject jsonObject = userArray.getJSONObject(i);
                String userId = jsonObject.getString("userId");
                if (userIdStr.equals(userId)) {
                    String userPhone = jsonObject.getString("phone");
                    map.put(phoneKey, userPhone);
                    break;
                }
            }
        }
    }

    /**
     * 获取用户手机号
     * @param userIds
     */
    JSONArray getUserPhone(String userIds) throws ServiceException {
        URI user = util.getServiceUrl("user", "error requset url!");
        String url = user + "/v1.0/user/findPhoneByUserId";

        MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
        body.add("userIds", userIds);

        RestTemplate restTemplate = new RestTemplate();
        String result = restTemplate.postForObject(url, body, String.class);

        JSONObject jsonObject = JSONObject.fromObject(result);
        String respCode = jsonObject.getString(CommonConstants.RESP_CODE);
        String respMsg = jsonObject.getString(CommonConstants.RESP_MESSAGE);
        if (!CommonConstants.SUCCESS.matches(respCode)) {
            throw new ServiceException(respMsg);
        }
        jsonObject = jsonObject.getJSONObject("result");
        return jsonObject.getJSONArray("list");
    }

    private Specification<FreeQuickOrder> where(final String phone, final String requestNo, final String channelTag, final String startTimeStr, final String endTimeStr) throws ServiceException {
        return (root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (StringUtils.isNotBlank(phone)) {
                if (!phone.matches("^1\\d{10}$")) {
                    throw new ServiceException("手机号码输入错误！");
                }
                JSONObject jsonObject = getUserIdByPhone(phone);
                String userId = jsonObject.getLong("userId") + "";
                predicates.add(criteriaBuilder.equal(root.<String>get("userId"), userId));
            }
            if (StringUtils.isNotBlank(requestNo)) {
                predicates.add(criteriaBuilder.equal(root.<String>get("requestNo"), requestNo));
            }
            if (StringUtils.isNotBlank(channelTag)) {
                predicates.add(criteriaBuilder.equal(root.<String>get("requestNo"), requestNo));
            }
            predicates.add(criteriaBuilder.equal(root.<String>get("payStatus"), "1"));
            if (StringUtils.isNotBlank(startTimeStr) && StringUtils.isNotBlank(endTimeStr)) {
                predicates.add(criteriaBuilder.greaterThan(root.<Date>get("createTime"), DateUtil.getYYMMHHMMSSDateFromStr(startTimeStr)));
                predicates.add(criteriaBuilder.lessThan(root.<Date>get("createTime"), DateUtil.getYYMMHHMMSSDateFromStr(endTimeStr)));
            }
            return criteriaQuery.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
        };
    }

    private JSONObject getUserIdByPhone(String phone) throws ServiceException{
        URI user = util.getServiceUrl("user", "error");
        String url = user + "/v1.0/user/findUserIdByPhone";

        MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
        body.add("phone", phone);
        body.add("brandId", 407L);

        RestTemplate restTemplate = new RestTemplate();
        String result = restTemplate.postForObject(url, body, String.class);

        JSONObject jsonObject = JSONObject.fromObject(result);
        String respCode = jsonObject.getString(CommonConstants.RESP_CODE);
        String respMsg = jsonObject.getString(CommonConstants.RESP_MESSAGE);
        if (!CommonConstants.SUCCESS.equals(respCode)) {
            throw new ServiceException(respMsg);
        }

        return jsonObject.getJSONObject(CommonConstants.RESULT);
    }

    // 提现状态：INIT待确认，REMITING出款中，SUCCESS出款成功，FAIL出款失败，UNKNOW未知
    private String remitStatus(String remitStatus) {
        // payStatus = 4
        if ("REMITING".equals(remitStatus)) {
            return "体现中";
        }
        // payStatus = 1
        if ("SUCCESS".equals(remitStatus)) {
            return "提现成功";
        }
        // payStatus = 0
        if ("FAIL".equals(remitStatus) || "UNKNOW".equals(remitStatus)) {
            return "待提现";
        }
        return "待确认";
    }

    // 根据开店管家商户编号获取畅捷平台商户编号
    private String getMerchantNo(String merchantNo) throws ServiceException {
        URI user = util.getServiceUrl("user", "error url request!");
        String url = user + "/v1.0/user/freeQtuick/queryMerchantNo";

        MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
        body.add("merchantNo", merchantNo);

        RestTemplate restTemplate = new RestTemplate();
        String result = restTemplate.postForObject(url, body, String.class);

        JSONObject jsonObject = JSONObject.fromObject(result);
        String respCode = jsonObject.getString(CommonConstants.RESP_CODE);
        if (!CommonConstants.SUCCESS.equals(respCode)) {
            String respMsg = jsonObject.getString(CommonConstants.RESP_MESSAGE);
            throw new ServiceException(respMsg);
        }

        jsonObject = jsonObject.getJSONObject(CommonConstants.RESULT);
        return jsonObject.getString("merchantNo");
    }

    public Map<String,String> queryMerct(String phone) {
        FreeQuickRequest request = new FreeQuickRequest(CommonConstants.AGENT_NO, CommonConstants.AGENT_KEY);
        Map<String,String> pram = queryLogin(phone);
        String result = MapUtils.getString(pram,"result");
        Map<String,String> param = JSONObject.fromObject(result);
        String merchantNo = MapUtils.getString(param,"merchantNo");
        String userId = MapUtils.getString(param,"userId");
        request.setSupportSign(false);
        request.setEncryptType(EncryptTypeEnum.AES);
        request.addParam("merchantNo", merchantNo);//商户编号
        log.info("response:" + request.toString());
        FreeQuickResponse response = FreeQuickClient.post(CommonConstants.QUERY_AMOUNT_URL,request);
        log.info("response:" + JSON.toJSONString(response));
        Map<String, String> resp = response.getResultMap();
        resp.put("userId",userId);
        return resp;
    }

    @Override
    public Map<String, Object> appNoCardRebatePage(long userId, Pageable pageable) throws ServiceException {
        // 1、获取用户角色判断等级
        long roleId = getRole(userId);
        long isBrandIdUser;
        if (roleId == 2) {
            isBrandIdUser = 1;
        } else {
            isBrandIdUser = 0;
        }

        Map<String, Object> resMap = new LinkedHashMap<>();
        List<Map<String, Object>> list = new ArrayList<>();
        Page<FreeQuickOrder> quickOrderPage = freeQuickOrderRepository.findAll(where(userId, isBrandIdUser), pageable);

        List<FreeQuickOrder> content = quickOrderPage.getContent();
        if (content.size() == 0) {
            resMap.put("content", content);
        } else {
            for (FreeQuickOrder order : content) {
                String requestNo = order.getRequestNo();
                String merchantNo = order.getMerchantNo();
                BigDecimal inAmount = order.getInAmount();

                BigDecimal rebate;
                if (roleId == 2) {
                    // 贴牌商角色
                    rebate = order.getBrandAmount();
                } else {
                    rebate = order.getGradeAmount();
                }

                String payType = order.getPayType();
                String createTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(order.getCreateTime());

                Map<String, Object> map = new LinkedHashMap<>();
                map.put("requestNo", requestNo);
                map.put("merchantNo", merchantNo);
                map.put("inAmount", inAmount);
                map.put("rebate", rebate);
                map.put("payType", payType);
                map.put("createTime", createTime);

                list.add(map);
            }
            resMap.put("content", list);
        }

        resMap.put("first", quickOrderPage.isFirst());
        resMap.put("last", quickOrderPage.isLast());
        resMap.put("totalElements", quickOrderPage.getTotalElements());
        resMap.put("totalPages", quickOrderPage.getTotalPages());
        resMap.put("number", quickOrderPage.getNumber());
        resMap.put("size", quickOrderPage.getSize());
        resMap.put("sort", quickOrderPage.getSort());
        resMap.put("numberOfElement", quickOrderPage.getNumberOfElements());
        return resMap;
    }

    private long getRole(long userId) throws ServiceException {
        URI user = util.getServiceUrl("user", "error request url!");
        String url = user + "/v1.0/user/app/findRoleId";

        MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
        body.add("userId", userId);

        RestTemplate restTemplate = new RestTemplate();
        String result = restTemplate.postForObject(url, body, String.class);

        JSONObject jsonObject = JSONObject.fromObject(result);
        String respCode = jsonObject.getString(CommonConstants.RESP_CODE);
        String respMsg = jsonObject.getString(CommonConstants.RESP_MESSAGE);
        if (!CommonConstants.SUCCESS.equals(respCode)) {
            throw new ServiceException(respMsg);
        }

        jsonObject = jsonObject.getJSONObject("result");
        return jsonObject.getLong("roleId");
    }

    private Specification<FreeQuickOrder> where(final long userId, final long isBrandIdUser) {
        return (root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (userId != 0) {
                if (isBrandIdUser == 1) {
                    predicates.add(criteriaBuilder.equal(root.<String>get("brandUserId"), userId + ""));
                }
                if (isBrandIdUser == 0) {
                    predicates.add(criteriaBuilder.equal(root.<String>get("preUserId"), userId + ""));
                }
            }
            predicates.add(criteriaBuilder.equal(root.<String>get("payStatus"), "1"));
            return criteriaQuery.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
        };
    }
}
